package com.uuah.server.session;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.config.i18n.CoreMessages;
import com.uuah.server.api.IUuahContext;
import com.uuah.server.api.IUuahEvent;
import com.uuah.server.api.IUuahMessage;
import com.uuah.server.api.component.service.IService;
import com.uuah.server.api.endpoint.IUuahEndpoint;
import com.uuah.server.api.session.ISessionHandler;
import com.uuah.server.api.session.IUuahSession;
import com.uuah.server.api.transport.IConnector;
import com.uuah.server.config.Constants;
import com.uuah.server.config.i18n.ServerMessages;
import com.uuah.server.exception.AbstractUuahServerException;
import com.uuah.server.exception.transport.DispatchException;
import com.uuah.server.transport.AbstractConnector;
import com.uuah.server.transport.RequestContextHelper;
import com.uuah.utils.UUID;

/**
 *
 * TODO comment ...
 *
 * <p>
 * update record:updator，update time，update content and version
 * </p>
 *
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-3-27 下午02:03:01
 * @version 1.0.0
 */
public final class UuahSession implements IUuahSession {

	private static final long serialVersionUID = 3380926585676521866L;
	private transient Logger logger = LoggerFactory.getLogger(UuahSession.class);

	private transient IService service = null;
	private boolean valid = true;

	private String id;

	private Map properties = null;

	private transient IUuahContext uuahContext;

	public UuahSession(IService service, IUuahContext uuahContext) {
		this.uuahContext = uuahContext;
		properties = new HashMap();
		id = UUID.getTimeBasedUUIDString();
		this.service = service;
	}

	public UuahSession(IUuahMessage message,
			ISessionHandler requestSessionHandler, IService service,
			IUuahContext uuahContext) throws AbstractUuahServerException {
		this(message, requestSessionHandler, uuahContext);
		if (service == null) {
			throw new IllegalArgumentException(ServerMessages.propertiesNotSet(
					"service").toString());
		}
		this.service = service;
	}

	public UuahSession(IUuahMessage message,
			ISessionHandler requestSessionHandler, IUuahContext uuahContext)
			throws AbstractUuahServerException {
		this.uuahContext = uuahContext;

		if (requestSessionHandler == null) {
			throw new IllegalArgumentException(ServerMessages.propertiesNotSet(
					"requestSessionHandler").toString());
		}

		if (message == null) {
			throw new IllegalArgumentException(ServerMessages.propertiesNotSet(
					"message").toString());
		}

		properties = new HashMap();
		requestSessionHandler.retrieveSessionInfoFromMessage(message, this);
		id = (String) getProperty(requestSessionHandler.getSessionIDKey());
		if (id == null) {
			id = UUID.getTimeBasedUUIDString();
			if (logger.isDebugEnabled()) {
				logger
						.debug("There is no session id on the request using key: "
								+ requestSessionHandler.getSessionIDKey()
								+ ". Generating new session id: " + id);
			}
		} else if (logger.isDebugEnabled()) {
			logger.debug("Got session with id: " + id);
		}
	}

	public void dispatchEvent(IUuahMessage message)
			throws AbstractUuahServerException {
		if (service == null) {
			throw new IllegalStateException(CoreMessages
					.objectIsNull("Service").getMessage());
		}

		// router.route(message, this);
	}

	public void dispatchEvent(IUuahMessage message, String endpointName)
			throws AbstractUuahServerException {
		dispatchEvent(message, uuahContext.getRegistry().lookupEndpointFactory()
				.getRequestEndpoint(endpointName));
	}

	public void dispatchEvent(IUuahMessage message, IUuahEndpoint endpoint)
			throws AbstractUuahServerException {
		if (endpoint == null) {
			logger
					.warn("Endpoint argument is null, using request router to determine endpoint.");
			dispatchEvent(message);
		}

		if (logger.isDebugEnabled()) {
			logger.debug("UuahSession has received asynchronous event on: "
					+ endpoint);
		}
	}

	public IUuahMessage sendEvent(IUuahMessage message)
			throws AbstractUuahServerException {
		if (service == null) {
			throw new IllegalStateException(CoreMessages
					.objectIsNull("Service").getMessage());
		}
		// ͬ�������¼�������ӿ�
		return message;
	}

	public void dispatchEvent(IUuahEvent event)
			throws AbstractUuahServerException {
		if (service != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("dispatching event to service: "
						+ service.getName() + ", event is: " + event);
			}
			service.dispatchEvent(event);
		} else {
			throw new DispatchException(
					ServerMessages.noComponentForEndpoint(),
					event.getMessage(), event.getEndpoint());
		}
	}

	public String getId() {
		return id;
	}

	public IUuahMessage sendEvent(IUuahEvent event)
			throws AbstractUuahServerException {
		int timeout = event.getMessage().getIntProperty(
				Constants.UUAH_EVENT_TIMEOUT_PROPERTY, -1);
		if (timeout >= 0) {
			event.setTimeout(timeout);
		}

		if (service != null) {
			try {
				if (logger.isDebugEnabled()) {
					logger.debug("sending event: " + event);
				}

				IConnector connector = event.getEndpoint().getConnector();

				if (connector instanceof AbstractConnector) {
					((AbstractConnector) connector)
							.getSessionHandler()
							.storeSessionInfoToMessage(this, event.getMessage());
				} else {
					logger
							.warn("A session handler could not be obtained, using default.");
					new UuahSessionHandler().storeSessionInfoToMessage(this,
							event.getMessage());
				}
				if (logger.isDebugEnabled()) {
					logger.debug("sending event to service: "
							+ service.getName() + " event is: " + event);
				}
				IUuahMessage response = service.sendEvent(event);
				response = RequestContextHelper.unsafeRewriteEvent(response);
				return response;
			} catch (AbstractUuahServerException e) {
				throw e;
			} catch (Exception e) {
				throw new DispatchException(event.getMessage(), event
						.getEndpoint(), e);
			}

		} else {
			throw new DispatchException(
					ServerMessages.noComponentForEndpoint(),
					event.getMessage(), event.getEndpoint());
		}
	}

	public IService getService() {
		return service;
	}

	public void setService(IService service) {
		this.service = service;
	}

	public void setProperty(Object key, Object value) {
		properties.put(key, value);
	}

	public Object getProperty(Object key) {
		return properties.get(key);
	}

	public Object removeProperty(Object key) {
		return properties.remove(key);
	}

	public Iterator getPropertyNames() {
		return properties.keySet().iterator();
	}
}
